use std::borrow::Cow;
use thiserror::Error;

pub type IoErr = std::io::Error;
pub type SqlxErr = sqlx::Error;

#[derive(Debug, Error)]
pub enum AppErr {

    #[error("io:{0}")]
    Io(#[from] IoErr),

    #[error("sqlx:{0}")]
    Sqlx(#[from] SqlxErr),

    #[error("{0}")]
    Wrap(Cow<'static, str>),
}   

impl AppErr {

    pub fn new_with_static(msg: &'static str) -> AppErr {
        AppErr::Wrap(Cow::Borrowed(msg))
    }

    pub fn new(msg: String) -> AppErr {
        AppErr::Wrap(Cow::Owned(msg))
    }
}


pub trait ErrWrap<T> {
    
    fn wrap(self) -> Result<T, AppErr>; 
}

impl <T, E: std::error::Error> ErrWrap<T> for Result<T, E> {

    fn wrap(self) -> Result<T, AppErr> {
        match self {
            Ok(v) => Ok(v),
            Err(e) => Err(AppErr::new(e.to_string()))
        }
    }
}

impl <T> ErrWrap<T> for Option<T> {

    fn wrap(self) -> Result<T, AppErr> {
        match self {
            Some(v) => Ok(v),
            None => Err(AppErr::new_with_static("option is none"))
        }
    }
}




